Function: diff-context->unified

diff-context->unified is an interactive and byte-compiled function defined in diff-mode.el.gz.

Signature

(diff-context->unified START END &optional TO-CONTEXT)

Documentation

Convert context diffs to unified diffs.

START and END are either taken from the region
(when it is highlighted) or else cover the whole buffer.
With a prefix argument, convert unified format to context format.

View in manual

Probably introduced at or before Emacs version 22.1.

Key Bindings

Source Code

;; Defined in /usr/src/emacs/lisp/vc/diff-mode.el.gz
(defun diff-context->unified (start end &optional to-context)
  "Convert context diffs to unified diffs.
START and END are either taken from the region
\(when it is highlighted) or else cover the whole buffer.
With a prefix argument, convert unified format to context format."
  (interactive (if (use-region-p)
		   (list (region-beginning) (region-end) current-prefix-arg)
		 (list (point-min) (point-max) current-prefix-arg)))
  (if to-context
      (diff-unified->context start end)
    (unless (markerp end) (setq end (copy-marker end t)))
    (let ( ;;(diff-inhibit-after-change t)
          (inhibit-read-only t))
      (save-excursion
        (goto-char start)
        (while (and (re-search-forward "^\\(\\(\\*\\*\\*\\) .+\n\\(---\\) .+\\|\\*\\{15\\}.*\n\\*\\*\\* \\([0-9]+\\),\\(-?[0-9]+\\) \\*\\*\\*\\*\\)\\(?: \\(.*\\)\\|$\\)" nil t)
                    (< (point) end))
          (combine-after-change-calls
            (if (match-beginning 2)
                ;; we matched a file header
                (progn
                  ;; use reverse order to make sure the indices are kept valid
                  (replace-match "+++" t t nil 3)
                  (replace-match "---" t t nil 2))
              ;; we matched a hunk header
              (let ((line1s (match-string 4))
                    (line1e (match-string 5))
                    (pt1 (match-beginning 0))
                    ;; Variables to use the special undo function.
                    (old-undo buffer-undo-list)
                    (old-end (marker-position end))
                    ;; We currently throw away the comment that can follow
                    ;; the hunk header.  FIXME: Preserve it instead!
                    (reversible (not (match-end 6))))
                (replace-match "")
                (unless (re-search-forward
                         diff-context-mid-hunk-header-re nil t)
                  (error "Can't find matching `--- n1,n2 ----' line"))
                (let ((line2s (match-string 1))
                      (line2e (match-string 2))
                      (pt2 (progn
                             (delete-region (progn (beginning-of-line) (point))
                                            (progn (forward-line 1) (point)))
                             (point-marker))))
                  (goto-char pt1)
                  (forward-line 1)
                  (while (< (point) pt2)
                    (pcase (char-after)
                      (?! (delete-char 2) (insert "-") (forward-line 1))
                      (?- (forward-char 1) (delete-char 1) (forward-line 1))
                      (?\s              ;merge with the other half of the chunk
                       (let* ((endline2
                               (save-excursion
                                 (goto-char pt2) (forward-line 1) (point))))
                         (pcase (char-after pt2)
                           ((or ?! ?+)
                            (insert "+"
                                    (prog1
                                        (buffer-substring (+ pt2 2) endline2)
                                      (delete-region pt2 endline2))))
                           (?\s
                            (unless (= (- endline2 pt2)
                                       (- (line-beginning-position 2) (point)))
                              ;; If the two lines we're merging don't have the
                              ;; same length (can happen with "diff -b"), then
                              ;; diff-unified->context will not properly undo
                              ;; this operation.
                              (setq reversible nil))
                            (delete-region pt2 endline2)
                            (delete-char 1)
                            (forward-line 1))
                           (?\\ (forward-line 1))
                           (_ (setq reversible nil)
                              (delete-char 1) (forward-line 1)))))
                      (_ (setq reversible nil) (forward-line 1))))
                  (while (looking-at "[+! ] ")
                    (if (/= (char-after) ?!) (forward-char 1)
                      (delete-char 1) (insert "+"))
                    (delete-char 1) (forward-line 1))
                  (save-excursion
                    (goto-char pt1)
                    (insert "@@ -" line1s ","
                            (number-to-string (- (string-to-number line1e)
                                                 (string-to-number line1s)
                                                 -1))
                            " +" line2s ","
                            (number-to-string (- (string-to-number line2e)
                                                 (string-to-number line2s)
                                                 -1)) " @@"))
                  (set-marker pt2 nil)
                  ;; The whole procedure succeeded, let's replace the myriad
                  ;; of undo elements with just a single special one.
                  (unless (or (not reversible) (eq buffer-undo-list t))
                    (setq buffer-undo-list
                          (cons (list 'apply (- old-end end) pt1 (point)
                                      'diff-unified->context pt1 (point))
                                old-undo)))
                  )))))))))